package client

import (
	"gitee.com/igolang/pkg/xcfg"
	"gitee.com/igolang/pkg/xgorm"
	"github.com/pkg/errors"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"sync"
)

var mc = &mysqlClient{
	clients: make(map[string]*gorm.DB),
}

type mysqlClient struct {
	clients map[string]*gorm.DB
	sync.RWMutex
}

func (c *mysqlClient) add(name string, db *gorm.DB) {
	c.Lock()
	defer c.Unlock()
	c.clients[name] = db
}

func (c *mysqlClient) get(name string) *gorm.DB {
	c.RLock()
	defer c.RUnlock()
	return c.clients[name]
}

func (c *mysqlClient) close() error {
	c.Lock()
	defer c.Unlock()
	errs := make([]error, 0)
	for _, v := range c.clients {
		if v == nil {
			continue
		}
		db, err := v.DB()
		if err != nil {
			errs = append(errs, err)
			continue
		}
		if err := db.Close(); err != nil {
			errs = append(errs, err)
		}
	}
	if len(errs) > 0 {
		return errors.Errorf("%+v", errs)
	}
	return nil
}

func (c *mysqlClient) Init() error {
	m := xcfg.GetStringMapStringSlice("database")
	for k := range m {
		db, err := InitDB(k)
		if err != nil {
			return err
		}
		SetDB(k, db)
	}
	return nil
}

func (c *mysqlClient) initDefaultMysql() error {
	name := DefaultMysql
	db, err := InitDB(name)
	if err != nil {
		return err
	}
	c.add(name, db)
	return nil
}

func (c *mysqlClient) Shutdown() error {
	return c.close()
}

func DB(names ...string) *gorm.DB {
	name := DefaultMysql
	if len(names) > 0 {
		name = names[0]
	}
	return mc.get(name)
}

func SetDB(name string, db *gorm.DB) {
	mc.add(name, db)
}

func InitDB(name string) (*gorm.DB, error) {
	key := "database." + name
	if !xcfg.IsSet(key) {
		return nil, errors.New("mysql default config nil")
	}
	cfg := &xgorm.ConnConfig{}
	if err := xcfg.UnmarshalKey(key, cfg); err != nil {
		return nil, errors.Errorf("parse mysql config err: %v", err)
	}
	dsn := xcfg.GetString(key + ".dsn")
	return xgorm.NewMysqlDBByDsn(dsn, cfg, logger.Default)

}
